#include "GL/GLRenderTexture.h"
#include "GL/GLTexture.h"
#include "Logger.h"
#include "Exception.h"
#include <sstream>

NS_B2D_BEGIN

struct GLRenderTexture::TempEditBind
{
	bool restore;
	GLint tmpName;
	TempEditBind(GLuint fboName)
		: restore(false)
	{
		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &tmpName);
		if( tmpName != fboName )
		{
			glBindFramebuffer(GL_FRAMEBUFFER, fboName);
			restore = true;
		}
	}
	~TempEditBind(void)
	{
		if( restore )
			glBindFramebuffer(GL_FRAMEBUFFER, tmpName);
	}
};

GLRenderTexture::GLRenderTexture(size_t texCount)
	: RenderTexture(texCount)
{
	create();
}

GLRenderTexture::~GLRenderTexture(void)
{
	destroy();
}


void GLRenderTexture::resizeImpl(void)
{
	// Resize textures
	// Empty contents?
	for(size_t i = 0; i < mTextureCount; ++i)
	{
		TexturePtr tex = mTextures[i];
		tex->initialiseWithData(nullptr, mSize.x, mSize.y, tex->getFormat(),tex->hasMipmaps());
		// TODO SP
		//tex->initialiseWithData(tex->getPixelData(), mWidth, mHeight,tex->getFormat(),tex->hasMipmaps());
	}
}

void GLRenderTexture::create(void)
{

	// Create & bind FBO
	glGenFramebuffers(1, &mFBO);
	TempEditBind tmpBind(mFBO);
	GLenum drawBuffers[MAX_TEXTURE_ATTACHMENTS];

	for(size_t i = 0; i < mTextureCount; ++i)
	{
		// Create texture
		std::stringstream ss;
		ss << "GLRenderTexture_" << mFBO << "_" << i; // GLRenderTexture_[fboName]_[textureIndex]
		std::shared_ptr<GLTexture> tex(new GLTexture());
		tex->initialiseWithData(nullptr, mSize.x, mSize.y, TextureFormat::RGBA8, false);
		mTextures[i] = tex;

		// Attach to FBO
		GLuint texHandle = tex->getGLName();
		drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
		glFramebufferTexture2D(GL_FRAMEBUFFER, drawBuffers[i], GL_TEXTURE_2D, texHandle, 0);
	}
		
	glDrawBuffers(mTextureCount, drawBuffers);
		
	// Check for errors
	GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	if( err == GL_FRAMEBUFFER_COMPLETE )
	{
		B2D_LOG_DEBUG("Frame buffer created with with id(%i) and %i texture attachments", mFBO, mTextureCount);
	}
	else
	{
		B2D_THROW(Exception::GRAPHICS_API_EXCEPTION,
			"Could not create OpenGL frame buffer object and attach requested textures to it");
	}
}

void GLRenderTexture::destroy(void)
{
	// Delete FBO
	if( mFBO != 0 )
	{
		B2D_LOG_DEBUG("Frame buffer with id(%i) was destroyed", mFBO);
		glDeleteFramebuffers(1, &mFBO);
		mFBO = 0;
	}
	mTextureCount = 0;
}


NS_B2D_END